This is a JavaScript practice with JavaScript30 by Wes Bos without any frameworks, no compilers, no boilerplate, and no libraries.
view demo here
<input>
elements and addEventListener
const checkboxes = document.querySelectorAll('.inbox input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.addEventListener( 'click', handleCheck )); // `click` also fire when use keyboard
lastChecked
this
inBetween
’s inputs .checked = true
;let lastChecked;
function handleCheck(e) {
// console.log(e);
// check if they have shift key down
// and check that they are checking it
let inBetween = false;
if(e.shiftKey && this.checked) {
// go ahead and do what we please
// loop over every single checkbox
checkboxes.forEach(checkbox => {
console.log(checkbox);
if(checkbox === this || checkbox === lastChecked) {
inBetween = !inBetween;
console.log('Starting to check them inbetween');
}
if(inBetween) {
checkbox.checked = true;
}
});
}
lastChecked = this;
}
we defines the range of inBetween
by checkbox === this
and checkbox === lastChecked
checking all inputs, if it’s one of the two inputs we checked, then flip the inBetween = true
, and set all the inBetween = true
inputs ‘ .checked = true
let’s take a look in a pseudo-code way, and I always like to use this way :)
let inBetween = false;
// first seleted b, then hold shiftKey and slected d
//start checking
[ ] a <- inBetween = false, it doesn't event get in the if condition
[v] b <- inBetween = true, b is the checked input 'lastChecked', and inBetween starts to flip to true
[v] c <- inBetween = true
[v] d <- inBetween = false, d is the checked input 'this', and its inBetween is fliped from true to false, then the checking ended as well.
[ ] e <- inBetween = x, it doesn't get in the if condition
I’ve got stuck in a long time for that iteraling to the input c, how come its inBetween
is true, seems like it doesn’t match either checkbox === this
or checkbox === lastChecked
, is beacuse the inBetween
had fliped to true so that it’s true when checking on input c, right ?
hope this way will help you understand much better like I did.
I guess the above two problems both are the same logic issues.
The figure above shows the problem 1 result I’d tried, and I think that is because in this case only has a seleted input just right equals the checkbox === lastChecked
and some how it treat the last input as the checkbox === this
, so it will iteral over all the rest of inputs (after the one we seleted), and set the inBetween = true
till the end.
Here is one of solutions I found on stack overflow: How can I shift-select multiple checkboxes like GMail?
const checkboxes = document.querySelectorAll('.inbox input[type="checkbox"]');
const checkboxesArray = [...checkboxes]; // fixup-step-1: turn the NodeList into an Array
e.shfitKey
is true, use array.indexOf()
to get the index of seleted inputs in the array to define the range (say the range containts the start point like checkbox === lastChecked
and end point like checkbox === this
)let start = checkboxesArray.indexOf(lastChecked);
let end = checkboxesArray.indexOf(this);
let
the checkState
variable is false
, it represents the inputs in the range which are checked or notlet checkState = false;
array.slice()
to take all the elements between the range and change their checkState
to checkedcheckboxesArray
.slice(Math.min(start, end), Math.max(start, end) + 1)
.forEach(input => input.checked = checkState);
const checkboxes = document.querySelectorAll('.inbox input[type="checkbox"]');
const checkboxesArray = [...checkboxes]; // fixup-step-1
let checkState = false; // fixup-step-3
function handleCheck(e) {
if(!lastChecked) { lastChecked = this; } // mark the lastChecked to redefine the range
checkState = lastChecked.checked ? true : false; // checked or unchecked
if(e.shiftKey) {
// fixup-step-2
let start = checkboxesArray.indexOf(lastChecked);
let end = checkboxesArray.indexOf(this);
// fixup-step-4
checkboxesArray
.slice(Math.min(start, end), Math.max(start, end) + 1)
.forEach(input => input.checked = checkState);
if(start - end < 0) {
console.log(`from first selected input ${start} to second selected input ${end} are checked`);
} else {
console.log(`[Backforwad]form first selected input ${start} to second selected input ${end} are checked`);
}
}
lastChecked = this;
}
well then…now it seems much better, but I think there are some other tiny problems…